#include <stdio.h>
#include <string.h>
#include <curl.h>
#include <openssl/sha.h>
#include "ota_http.h"
#include "thirdparty/cJSON/cJSON.h"
#include "thirdparty/log.c/log.h"
#include <stdlib.h>

#define BUFFER_SIZE 1024

typedef struct
{
    char *memory;
    size_t size;
} MemoryStruct;

// 内存写入回调函数，用于CURL接收数据
static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
    // 计算实际接收到的数据大小
    size_t realsize = size * nmemb;
    MemoryStruct *mem = (MemoryStruct *)userp;

    // 重新分配内存以容纳新数据
    char *ptr = realloc(mem->memory, mem->size + realsize + 1);
    if (ptr == NULL)
    {
        // 内存不足处理
        log_error("Not enough memory (realloc returned NULL)");
        return 0; // 返回0表示失败，CURL会终止传输
    }

    // 更新内存指针
    mem->memory = ptr;
    // 将新数据追加到内存缓冲区
    memcpy(&(mem->memory[mem->size]), contents, realsize);
    // 更新已接收数据大小
    mem->size += realsize;
    // 添加字符串终止符
    mem->memory[mem->size] = 0;

    // 返回实际处理的数据大小
    return realsize;
}

int ota_http_getVersion(Version *version)
{
    CURL *curl;         // CURL对象指针，用于HTTP请求
    CURLcode res;       // CURL操作返回码
    MemoryStruct chunk; // 内存缓冲区结构体
    long response_code; // HTTP响应码

    // 初始化内存缓冲区
    chunk.memory = malloc(1); // 初始分配1字节缓冲区
    chunk.size = 0;           // 当前数据长度为0

    // 初始化CURL会话
    curl = curl_easy_init();
    if (curl)
    {
        // 设置CURL选项
        curl_easy_setopt(curl, CURLOPT_URL, VERSION_URL);                   // 设置请求URL
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); // 设置回调函数
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);          // 设置回调数据

        // 执行HTTP请求
        res = curl_easy_perform(curl);

        // 检查请求是否成功
        if (res != CURLE_OK)
        {
            log_error("curl_easy_perform() failed: %s", curl_easy_strerror(res));
            free(chunk.memory);
            curl_easy_cleanup(curl);
            return -1;
        }

        // 获取HTTP响应状态码
        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
        if (response_code != 200) // 检查是否为200 OK
        {
            log_error("HTTP request failed with status code: %ld", response_code);
            free(chunk.memory);
            curl_easy_cleanup(curl);
            return -1;
        }

        // 解析JSON响应
        cJSON *json = cJSON_Parse(chunk.memory);
        if (json == NULL)
        {
            log_error("Failed to parse JSON");
            free(chunk.memory);
            curl_easy_cleanup(curl);
            return -1;
        }

        // 从JSON中提取版本信息
        cJSON *major = cJSON_GetObjectItemCaseSensitive(json, "major");
        cJSON *minor = cJSON_GetObjectItemCaseSensitive(json, "minor");
        cJSON *patch = cJSON_GetObjectItemCaseSensitive(json, "patch");

        // 验证JSON字段类型并提取值
        if (cJSON_IsNumber(major) && cJSON_IsNumber(minor) && cJSON_IsNumber(patch))
        {
            version->major = major->valueint;
            version->minor = minor->valueint;
            version->patch = patch->valueint;
        }
        else
        {
            log_error("Invalid JSON format");
            cJSON_Delete(json);
            free(chunk.memory);
            curl_easy_cleanup(curl);
            return -1;
        }

        // 清理资源
        cJSON_Delete(json);      // 释放JSON对象
        free(chunk.memory);      // 释放内存缓冲区
        curl_easy_cleanup(curl); // 清理CURL会话

        return 0; // 成功返回0
    }
    return -1; // CURL初始化失败返回-1
}

// 获取固件文件函数
int ota_http_getFirmware(char *file)
{
    CURL *curl;                            // CURL对象指针，用于HTTP请求
    CURLcode res;                          // CURL操作返回码
    FILE *fp;                              // 文件指针，用于写入下载的固件
    unsigned char hash[SHA_DIGEST_LENGTH]; // SHA1哈希值存储缓冲区
    SHA_CTX sha_ctx;                       // SHA1上下文
    char buffer[BUFFER_SIZE];              // 文件读写缓冲区
    size_t bytes_read;                     // 实际读取的字节数
    long response_code;                    // HTTP响应码

    // 以二进制写入模式打开文件
    fp = fopen(file, "wb");
    if (!fp)
    {
        log_error("Failed to open file %s for writing", file);
        return -1;
    }

    // 初始化CURL会话
    curl = curl_easy_init();
    if (curl)
    {
        // 设置CURL选项
        curl_easy_setopt(curl, CURLOPT_URL, FIRMWARE_URL); // 设置固件下载URL
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);     // 设置写入目标为文件

        // 初始化SHA1哈希计算
        SHA1_Init(&sha_ctx);

        // 执行HTTP请求
        res = curl_easy_perform(curl);
        if (res != CURLE_OK)
        {
            log_error("curl_easy_perform() failed: %s", curl_easy_strerror(res));
            fclose(fp);
            curl_easy_cleanup(curl);
            return -1;
        }

        // 获取HTTP响应状态码
        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
        if (response_code != 200) // 检查是否为200 OK
        {
            log_error("HTTP request failed with status code: %ld", response_code);
            fclose(fp);
            curl_easy_cleanup(curl);
            return -1;
        }

        // 计算下载文件的SHA1哈希值
        fseek(fp, 0, SEEK_SET); // 重置文件指针到文件开头
        while ((bytes_read = fread(buffer, 1, BUFFER_SIZE, fp)) > 0)
        {
            SHA1_Update(&sha_ctx, buffer, bytes_read); // 更新哈希计算
        }

        SHA1_Final(hash, &sha_ctx); // 完成哈希计算

        // 清理资源
        fclose(fp);
        curl_easy_cleanup(curl);

        return 0; // 成功返回0
    }

    // CURL初始化失败时的清理
    fclose(fp);
    return -1; // 失败返回-1
}
